#pragma once
#include <assert.h>
#include <iostream>
using namespace std;


namespace my_std
{
	class string
	{
	private:
		char* _str;
		size_t _size;
		size_t _capacity;

	public:

		typedef char* iterator;
		typedef const char* const_iterator;
 
		static size_t const npos;

		string(const char* str = "")
		{
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity + 1];
			memcpy(_str,str,_size + 1);

		}


		string(const string& str)
		{
			_str = new char[str._size + 1];
			_size = str._size;
			_capacity = str._capacity;
			memcpy(_str, str._str, _size + 1);
		}
		
		void swap(string& str)
		{
			std::swap(_str, str._str);
			std::swap(_size, str._size);
			std::swap(_capacity, str._capacity);
		}

		string& operator=(string str)
		{
			swap(str);
			return *this;
		}


		~string()
		{
			delete[] _str;
		}

		void push_back(const char ch)
		{
			if (_size == _capacity)
			{
				reserve(_capacity * 2);
				_capacity *= 2;
			}
			
			_str[_size++] = ch;
			_str[_size] = '\0';
		}

		void pop_back()
		{
			if (!_size)
			{
				return;
			}
			else
			{
				_size--;
			}
		}

		const char* c_str()const
		{
			return _str;
		}

		void reserve(size_t n = 0)
		{
			if (n > _capacity)
			{
				cout << "reserve()->" << n << endl;
				char* str = new char[n + 1];
				memcpy(str, _str,n + 1);
				delete[] _str;
				_str = str;
				_capacity = n;
				_str[_capacity] = '\0';
			}
		}

		iterator begin()
		{
			return _str;
		}
		const_iterator begin() const
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
		}
		const_iterator end() const
		{
			return _str + _size;
		}

		const size_t& size()const
		{
			return _size;
		}

		const size_t& capacity()const
		{
			return _capacity;
		}

		void clear()
		{
			_size = 0;
			_str[_size] = '\0';
		}

		bool empty()
		{
			return _size == 0;
		}

		char& operator[] (size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}
		const char& operator[] (size_t pos) const
		{
			assert(pos < _size);
			return _str[pos];
		}

		char& operator[] (iterator pos)
		{
			assert(pos < end());
			return *pos;
		}
		const char& operator[] (const_iterator pos) const
		{
			assert(pos < end());
			return *pos;
		}


		string& append(const string& str, size_t pos = 0, size_t n = npos)
		{
			size_t len = str._size;
			assert(pos < len);

			if (pos + n < len)
			{
				reserve(_size + n);
				
				memcpy(end(), str._str + pos, n);

				_size += n;
				_str[_size] = '\0';
			}
			else
			{
				reserve(_capacity + len - pos);

				memcpy(end(), str._str, len - pos + 1);

				_size += (len - pos);
			}

			return *this;

		}

		

		string& operator+=(const string& str)
		{
			return append(str);
		}

		string& operator+=(const char& ch)
		{
			push_back(ch);
			return *this;
		}


		void _insert(const string& str, size_t pos,size_t n)
		{
			size_t end = _size + n - 1;
			reserve(_size + n);
			size_t i = 0;
			while (i != n)
			{
				_str[end - i++] = _str[_size - 1 - i];
				_str[_size - i] = str[pos + n - i];
			}
			_size += n;
		}

		template<class InputIterator, class T>
		InputIterator find(InputIterator first, InputIterator last, const T& val)
		{
			while (first != last) {
				if (*first == val) return first;
				++first;
			}
			return last;
		}
		
		string& insert(const string& str, size_t pos = 0,size_t n = npos)
		{
			size_t len = str._size;
			assert(pos < len);

			if (pos + n < len)
			{
				_insert(str, pos, n);
			}
			else
			{
				_insert(str, pos, len - pos);
			}

			return *this;
		}



		const_iterator find(const string& str)const
		{
			return strstr(_str, str._str);
		}

		iterator find(const string& str)
		{
			return strstr(_str, str._str);
		}

		size_t find(const char* str)
		{
			char* p = strstr(_str, str);
			if (!p)
			{
				return npos;
			}
			else
			{
				int i = 0;
				while (*p != _str[i++]);
				return i - 1;

			}
		}

		size_t find(const char ch,size_t pos)
		{
			int i = pos;
			while (_str)
			{
				if (ch == _str[i])
				{
					return i;
				}
				i++;
			}
			return npos;
		}

		string substr(size_t pos1 = 0, size_t pos2 = npos)
		{
			string tmp;

			tmp.reserve(_size);

			memcpy(tmp._str, _str + pos1, pos2 - pos1);

			tmp._size = pos2 - pos1;
			tmp._str[tmp._size] = '\0';
			return tmp;
		}


		bool operator<(const string& str)const
		{
			int ret  = memcmp(_str, str._str, _size < str._size ? _size : str._size);

			return ret == 0 ? _size < str._size : ret < 0;
		}

		bool operator==(const string& str)const
		{
			return _size == str._size && !memcmp(_str, str._str, _size);
		}

		bool operator<=(const string& str)const
		{
			return  *this < str || * this == str;
		}

		bool operator>(const string& str)const
		{
			return !(*this <= str);
		}

		bool operator>=(const string& str)const
		{
			return !(*this < str);
		}


		bool operator!=(const string& str)const
		{
			return !(*this == str);
		}
	};
	size_t const string::npos = -1;

	ostream& operator<<(ostream& out, const string& str)
	{
		
		for (auto ch : str)
		{
			out << ch;
		}
		
		return out;
	}

	istream& operator>>(istream& in, string& str)
	{
		str.clear();

		char ch = in.get();
		while (ch == ' ' || ch == '\n')
		{
			ch = in.get();
		}

		char buff[200];
		int i = 0;
		while (ch != '\n')
		{
			buff[i] = ch;
			if (i == 199)
			{
				buff[i] = '\0';
				str += buff;
				i = 0;
			}
			i++;
			ch = in.get();
		}

		if (i != 0)
		{
			buff[i] = '\0';
			str += buff;
		}
		return in;
	}
};



